﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Reflection;
using System.Data;

namespace Model_SSResourceManager
{
    /// <summary>
    /// Base class for DB commands
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="EntityT"></typeparam>
    public abstract class ItemDataContext< T, EntityT >  where EntityT: class 
        where T: BaseModel  // T -type of Model, EntityT - type from Entity Framework
    {
        protected string EntitySetName;

        public bool Add(T _modelItem)
        {
            bool _result=false;

            EntityT entItem = Activator.CreateInstance<EntityT>();
            ModelToEntity(_modelItem, entItem);

            using ( SSRMDBEntities context = new SSRMDBEntities() )
            {
                try
                {
                    context.AddObject(EntitySetName, entItem);
                    context.SaveChanges();
                    _result = true;
                }
                catch (Exception ex)
                {
                    OnRaiceDbErrEvent(new DbErrEventArgs(ex.Message)); 
                }
            } 

            return _result;
        }

        public bool Delete(Guid _itemId)
        {
            bool _result = false;

            using (SSRMDBEntities context = new SSRMDBEntities())
            {
                try
                {
                    EntityT entItem = GetEntityItem(_itemId,context);
                    if (entItem != null)
                    {
                        context.DeleteObject(entItem);
                        context.SaveChanges();
                        _result = true;
                    }           
                }
                catch (Exception ex)
                {
                    OnRaiceDbErrEvent(new DbErrEventArgs(ex.Message));
                }
            }

            return _result;
        }

        public T Get(Guid _id)
        {
            T modelItem = Activator.CreateInstance<T>();

            using (SSRMDBEntities context = new SSRMDBEntities())
            {
                try
                {
                    EntityT entItem = GetEntityItem(_id, context);
                    if (entItem != null)
                        EntityToModel(entItem, modelItem);
                }
                catch (Exception ex)
                {
                    OnRaiceDbErrEvent(new DbErrEventArgs(ex.Message));
                }
            }

            return modelItem;
        }

        public List<T> GetAll()
        {
            List<T> _retList = new List<T>();

            using (SSRMDBEntities context = new SSRMDBEntities())
            {
                try
                {
                    ObjectSet<EntityT> entItemSet = GetEntitySet(context);
                    if ( entItemSet != null )
                    {
                        T modelItem ;
                        foreach (EntityT entItem in entItemSet)
                        {
                            modelItem = Activator.CreateInstance<T>();
                            EntityToModel(entItem, modelItem);
                            _retList.Add(modelItem);
                        }
                    }
                }
                catch (Exception ex)
                {
                    OnRaiceDbErrEvent(new DbErrEventArgs(ex.Message));
                }
            }

            return _retList;
        }

        public bool Update(T _modelItem)
        {
            bool _result=false;

            using (SSRMDBEntities context = new SSRMDBEntities())
            {
                try
                {
                    EntityT entItem = GetEntityItem(_modelItem.Id, context);
                    if (entItem != null)
                    {
                        ModelToEntity( _modelItem, entItem );
                        context.SaveChanges();
                        _result = true;
                    }
                }
                catch (Exception ex)
                {
                    OnRaiceDbErrEvent(new DbErrEventArgs(ex.Message));
                }
            }

            return _result;
        }

        /// <summary>
        /// Get SSRMDB item by Id
        /// </summary>
        /// <param name="_itemId"></param>
        /// <param name="_context"></param>
        /// <returns></returns>
        protected EntityT GetEntityItem(Guid _itemId,SSRMDBEntities _context)
        {
            EntityT entItem = null;
            
            EntityKey key = new EntityKey("SSRMDBEntities."+EntitySetName, "Id", _itemId);
            entItem = _context.GetObjectByKey(key) as EntityT;                    

            return entItem;
        }

        /// <summary>
        /// Get Entity ObjectSet by its Name
        /// </summary>
        /// <param name="_context"></param>
        /// <returns></returns>
        protected ObjectSet<EntityT> GetEntitySet(SSRMDBEntities _context)
        {
            ObjectSet<EntityT> entSet=null;
            PropertyInfo pInfo = _context.GetType().GetProperty(EntitySetName, BindingFlags.Public | BindingFlags.Instance) ;
            if (pInfo != null)
                entSet = pInfo.GetValue(_context, null) as ObjectSet<EntityT>;
            return entSet;
        }


        protected abstract void EntityToModel(EntityT _entItem, T _item);
        protected abstract void ModelToEntity(T _item, EntityT _entItem);

        #region Events
        public event EventHandler<DbErrEventArgs> DbErrEvent;

        protected void OnRaiceDbErrEvent(DbErrEventArgs e)
        {
            EventHandler<DbErrEventArgs> handler = DbErrEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion
    }
}
